﻿/**
 * @file speech_recog.c
 *
 */

/*********************
*      INCLUDES
*********************/
#include "lv_watch.h"

#if USE_LV_WATCH_SPEECH_RECOG != 0

/*********************
*      DEFINES
*********************/
#define SPEECH_RECOG_TEST 1
#define SPEECH_RECOG_AMR_HEAD_SIZE 6
#define SPEECH_RECOG_MAX_RECORD_DURATION 15 /*in seconds*/
#define SPEECH_RECOG_MAX_RECORD_SIZE SPEECH_RECOG_MAX_RECORD_DURATION * HAL_AMR_BUFSIZE_PER_SECOND + SPEECH_RECOG_AMR_HEAD_SIZE
#define SPEECH_RECOG_MAX_AUDIO_MSG_NUM 10
#define SPEECH_RECOG_MSG_SPACING 6
#define SPEECH_RECOG_MAX_AUDIO_LINE_NUM 4
#define SPEECH_RECOG_MAX_TEXT_LINE_NUM 4
#define SPEECH_RECOG_MAX_AUDIO_TEXT_LINE_NUM 2
#define SPEECH_RECOG_MAX_LINE_NUM ((SPEECH_RECOG_MAX_TEXT_LINE_NUM > SPEECH_RECOG_MAX_AUDIO_TEXT_LINE_NUM) ? SPEECH_RECOG_MAX_TEXT_LINE_NUM : SPEECH_RECOG_MAX_AUDIO_TEXT_LINE_NUM)

/**********************
*      TYPEDEFS
**********************/
enum {
    SPEECH_RECOG_MSG_FROM_USER = 0,
    SPEECH_RECOG_MSG_FROM_SERVER
};
typedef uint8_t speech_recog_msg_src_t;

enum {
    SPEECH_RECOG_MSG_TYPE_TEXT = 0,
    SPEECH_RECOG_MSG_TYPE_AUDIO
};
typedef uint8_t speech_recog_msg_type_t;

/**********************
*  STATIC PROTOTYPES
**********************/
static void speech_recog_set_user_num(lv_obj_t * obj, uint32_t user_num);
static void speech_recog_set_user_ptr(lv_obj_t * obj, void * user_ptr);
static uint32_t speech_recog_get_user_num(lv_obj_t * obj);
static void * speech_recog_get_user_ptr(lv_obj_t * obj);
static lv_res_t speech_recog_del_interface(lv_watch_Activity_Id_t act_id);
static void speech_recog_send_end_anim(void * para);
static void speech_recog_audio_anim_cb(lv_task_t * para);
static void speech_recog_img_back_event_cb(lv_obj_t * img, lv_event_t e);
static void speech_recog_voice_over_cb(void * para);
static void * speech_recog_get_ext(lv_watch_Activity_Id_t act_id);
static void speech_recog_play_audio_event_cb(lv_obj_t * cont, lv_event_t e);
static void speech_recog_add_msg(lv_speech_recog_ext_t * ext,
                                 char * text,
                                 speech_recog_msg_src_t src,
                                 speech_recog_msg_type_t type,
                                 uint8_t audio_index);
static void speech_recog_img_next_event_cb(lv_obj_t * img, lv_event_t e);
static lv_obj_t * speech_recog_create(lv_obj_t * activity_obj);
void speech_recog_audio_ctrl_callback(AUDIO_CTRL_PRIORITY priority);

#if SPEECH_RECOG_TEST != 0
#ifdef BUILD_IN_PC_SIMULATOR /*for pc test*/
static void Hal_Record_Buffer_Start_Req_1(uint8_t * buffer, uint32_t bufsize, uint32_t maxDurationMs, AUDIO_RECORD_CB_FUNC func);
static uint32_t Hal_Record_Buffer_Stop_Req_1(uint32_t * recSize, uint32_t * durationMs);
#endif
#endif

/**********************
*  STATIC VARIABLES
**********************/
#if SPEECH_RECOG_TEST != 0
static uint8_t test_num = 0;
#endif

/**********************
*      MACROS
**********************/

/**********************
 *   GLOBAL FUNCTIONS
 ***********************/
void speech_recog_create_event_cb(lv_obj_t * btn, lv_event_t e)
{
    (void)btn;
    if(LV_EVENT_CLICKED == e) {
        lv_watch_png_cache_all_free();
        lv_obj_t * obj = speech_recog_create(NULL);
        LV_ASSERT_MEM(obj);
    }
}

void app_adaptor_speech_recog_nw_search_cnf(char * text)
{
    printf("%s: text %p\n", __FUNCTION__, text);

    lv_speech_recog_send_ext_t * send_ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG_SEND);
    if(send_ext) {
        if(NULL == text) {
            /*network search failure*/
            lv_img_set_src(send_ext->img, ICON_SEARCH_FAILED);
            lv_anim_path_t path;
            lv_anim_path_init(&path);
            lv_anim_path_set_cb(&path, lv_anim_path_step);
            lv_anim_t a = {};
            lv_anim_init(&a);
            lv_anim_set_var(&a, send_ext->img);
            lv_anim_set_ready_cb(&a, (lv_anim_ready_cb_t)speech_recog_send_end_anim);
            lv_anim_set_time(&a, 2000);
            lv_anim_set_path(&a, &path);
            lv_anim_start(&a);
            return;
        } else {
            speech_recog_del_interface(ACT_ID_SPEECH_RECOG_SEND);
        }
    }

    if(text) {
        /*update txt to speech recog ui*/
        lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
        if(NULL == ext) {
            lv_mem_free(text);
            return;
        }
        speech_recog_add_msg(ext, text, SPEECH_RECOG_MSG_FROM_USER, SPEECH_RECOG_MSG_TYPE_TEXT, 0);
    }
}

void speech_recog_audio_ctrl_callback(AUDIO_CTRL_PRIORITY priority)
{
    printf("%s,priority is %d\n", __FUNCTION__,priority);
    if(AUDIO_CTRL_PRIORITY_4 > priority) {
        speech_recog_mt_call_ind();
    }
}

#if SPEECH_RECOG_TEST != 0
static void speech_recog_txt_msg_ind(char * text, uint8_t * voice_data)
{
    printf("%s: text %p, voice_data %p\n", __FUNCTION__, text, voice_data);

    if(NULL == text) return;

    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) {
        lv_mem_free(text);
        if(voice_data) lv_mem_free(voice_data);
        return;
    }
    speech_recog_add_msg(ext, text, SPEECH_RECOG_MSG_FROM_SERVER, SPEECH_RECOG_MSG_TYPE_TEXT, 0);
    if((NULL == lv_watch_get_activity_obj(ACT_ID_PHONE))
            && (false == phone_is_monitor_on())
            && (NULL == lv_watch_get_activity_obj(ACT_ID_ALARM))) {
        if(NULL != voice_data) {
            ext->voice_data = voice_data;
            Hal_NFFS_File_Play_Onetime((const char *)voice_data,
                                       query_current_volume(),
                                       speech_recog_voice_over_cb,
                                       NULL);
        }
    } else {
        if(voice_data) {
            lv_mem_free(voice_data);
        }
    }
}
#else
void app_adaptor_speech_recog_txt_msg_ind(char * text, uint8_t * voice_data, uint32_t voice_size)
{
    printf("%s: text %p, voice size %d\n", __FUNCTION__, text, voice_size);

    if(NULL == text) return;

    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) {
        lv_mem_free(text);
        if(voice_data) lv_mem_free(voice_data);
        return;
    }
    speech_recog_add_msg(ext, text, SPEECH_RECOG_MSG_FROM_SERVER, SPEECH_RECOG_MSG_TYPE_TEXT, 0);

    if(
#if 0
        (NULL == lv_watch_get_activity_obj(ACT_ID_PHONE))
            && (false == phone_is_monitor_on())
            && (NULL == lv_watch_get_activity_obj(ACT_ID_ALARM))
#else
        AUDIO_CTRL_PRIORITY_4
        == Hal_Audio_Manage_Start_Req(AUDIO_CTRL_PRIORITY_4, speech_recog_audio_ctrl_callback)
#endif
        ) {
        if((NULL != voice_data) && (0 != voice_size)) {
            ext->voice_data = voice_data;
            Hal_Tone_Play_Onetime((uint32_t *)voice_data,
                                  voice_size,
                                  query_current_volume(),
                                  speech_recog_voice_over_cb,
                                  NULL);
        }
    } else {
        if(voice_data) {
            lv_mem_free(voice_data);
        }
    }
}
#endif

void app_adaptor_speech_recog_audio_msg_ind(char * audio_text, uint8_t audio_index)
{
    if(NULL == audio_text) return;

    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) {
        lv_mem_free(audio_text);
        return;
    }

    printf("%s: audio num %d, text %p, index %d\n",
           __FUNCTION__, ext->audio_num, audio_text, audio_index);

    if(SPEECH_RECOG_MAX_AUDIO_MSG_NUM == ext->audio_num) {
        /*delete the top of the audio messages*/
        lv_obj_t * scrl = lv_page_get_scrl(ext->page);
        lv_coord_t height_scrl = lv_obj_get_height(scrl);
        lv_obj_t * child = lv_obj_get_child_back(scrl, NULL);
        lv_coord_t height = 0;
        while(NULL != child) {
            if(0 == height) {
                if(SPEECH_RECOG_MSG_TYPE_AUDIO == speech_recog_get_user_num(child)) {
                    /*delete audio message*/
                    height = lv_obj_get_height(child);
                    lv_obj_t * label_chat = lv_obj_get_child_back(child, NULL);
                    char * text = speech_recog_get_user_ptr(label_chat);
                    if(text) {
                        lv_mem_free(text);
                    }
                    lv_obj_del(child);
                }
            } else {
                lv_coord_t y = lv_obj_get_y(child);
                lv_obj_set_y(child, y - height - SPEECH_RECOG_MSG_SPACING);
            }
            child = lv_obj_get_child_back(scrl, child);
        }
        lv_obj_set_height(scrl, height_scrl - height - SPEECH_RECOG_MSG_SPACING);
    } else {
        ext->audio_num++;
    }
    speech_recog_add_msg(ext,
                         audio_text,
                         SPEECH_RECOG_MSG_FROM_SERVER,
                         SPEECH_RECOG_MSG_TYPE_AUDIO,
                         audio_index);
}

void app_adaptor_speech_recog_play_audio_cnf(uint16_t total_sec)
{
    printf("%s: total_sec %d\n", __FUNCTION__, total_sec);

    if(0 == total_sec) return;

    lv_speech_recog_audio_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG_AUDIO);
    if(NULL == ext) return;
    if(NULL == ext->img) return;

    lv_anim_del(ext->img, NULL);
    lv_obj_t * cont_bg = lv_obj_get_parent(ext->img);
    lv_img_set_src(ext->img, ICON_SPEECH_CLOSE);
    lv_obj_align(ext->img, cont_bg, LV_ALIGN_IN_BOTTOM_MID, 0, -10);
    lv_obj_set_click(ext->img, true);
    lv_obj_set_event_cb(ext->img, speech_recog_img_back_event_cb);
    speech_recog_set_user_num(ext->img, 0);
    lv_obj_set_adv_hittest(ext->img, false);
    lv_watch_obj_add_element(ext->img);

    ext->bar = lv_bar_create(cont_bg, NULL);
    lv_bar_set_range(ext->bar, 0, total_sec);
    lv_bar_set_value(ext->bar, 0, LV_ANIM_OFF);
    lv_obj_set_style_local_bg_color(ext->bar,
                                    LV_BAR_PART_BG,
                                    LV_STATE_DEFAULT,
                                    LV_COLOR_MAKE(132, 132, 255));
    lv_obj_set_style_local_radius(ext->bar,
                                  LV_BAR_PART_BG,
                                  LV_STATE_DEFAULT,
                                  0);
    lv_obj_set_style_local_border_opa(ext->bar,
                                  LV_BAR_PART_BG,
                                  LV_STATE_DEFAULT,
                                  LV_OPA_0);
    lv_obj_set_style_local_bg_color(ext->bar,
                                    LV_BAR_PART_INDIC,
                                    LV_STATE_DEFAULT,
                                    LV_COLOR_MAKE(210, 210, 255));
    lv_obj_set_style_local_radius(ext->bar,
                                  LV_BAR_PART_INDIC,
                                  LV_STATE_DEFAULT,
                                  0);
    lv_obj_set_size(ext->bar, lv_obj_get_width(cont_bg) * 4 / 5, 8);
    lv_obj_align(ext->bar, ext->img, LV_ALIGN_OUT_TOP_MID, 0, -10);

    lv_obj_t * label_total_time = lv_label_create(cont_bg, NULL);
    lv_obj_set_style_local_text_font(label_total_time,
                                     LV_LABEL_PART_MAIN,
                                     LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_SMALL);
    lv_obj_set_style_local_text_color(label_total_time,
                                      LV_LABEL_PART_MAIN,
                                      LV_STATE_DEFAULT,
                                      LV_COLOR_MAKE(132, 132, 255));
    char total_time[6] = {0};
    uint8_t min = total_sec / 60;
    if(60 <= min) {
        printf("warning! total time for audio exceeds one hour for speech recog\n");
        return;
    }
    uint8_t sec = total_sec % 60;
    snprintf(total_time, 6, "%02d:%02d", min, sec);
    lv_label_set_text(label_total_time, total_time);

    ext->label_time = lv_label_create(cont_bg, label_total_time);
    lv_label_set_text(ext->label_time, "00:00");

    if(LV_BIDI_DIR_RTL == lv_obj_get_base_dir(cont_bg)) {
        lv_obj_set_base_dir(ext->label_time, LV_BIDI_DIR_LTR);
        lv_obj_set_base_dir(label_total_time, LV_BIDI_DIR_LTR);
        lv_obj_align(ext->label_time, ext->bar, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, 2);
        lv_obj_align(label_total_time, ext->bar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 2);
    } else {
        lv_obj_align(label_total_time, ext->bar, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, 2);
        lv_obj_align(ext->label_time, ext->bar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 2);
    }
}

void app_adaptor_speech_recog_play_audio_ind(uint16_t cur_sec)
{
    printf("%s: cur_sec %d\n", __FUNCTION__, cur_sec);

    if(0 == cur_sec) return;

    lv_speech_recog_audio_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG_AUDIO);
    if(NULL == ext) return;

    uint16_t cur_value = lv_bar_get_value(ext->bar);
    if(cur_value >= cur_sec) {
        printf("%s: warning! new time less than current time\n", __FUNCTION__);
        return;
    }

    uint16_t max_value = lv_bar_get_max_value(ext->bar);
    ext->cur_max_value = cur_sec;
    if(max_value < ext->cur_max_value) {
        ext->cur_max_value = max_value;
    }

    uint8_t step = speech_recog_get_user_num(ext->img);
    if(0 < step) {
        lv_anim_del(ext->img, NULL);
        lv_img_set_src(ext->img, ICON_SPEECH_CLOSE);
        lv_obj_t * cont_bg = lv_obj_get_parent(ext->img);
        lv_obj_align(ext->img, cont_bg, LV_ALIGN_IN_BOTTOM_MID, 0, -10);
        lv_obj_set_click(ext->img, true);
        speech_recog_set_user_num(ext->img, 0);
    }

    if(NULL == ext->bar_task) {
        ext->bar_task = lv_task_create(speech_recog_audio_anim_cb, 1000, LV_TASK_PRIO_MID, ext);
    }
}

void speech_recog_mt_call_ind(void)
{
    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) return;

    lv_watch_Activity_Id_t act_id[3] = {
        ACT_ID_SPEECH_RECOG_SPEAK,
        ACT_ID_SPEECH_RECOG_AUDIO,
        ACT_ID_SPEECH_RECOG_SEND
    };
    lv_obj_t * activity_obj = NULL;
    lv_watch_activity_ext_t * act_ext = NULL;
    uint8_t i = 0;
    for(; i < 3; i++) {
        activity_obj = lv_watch_get_activity_obj(act_id[i]);
        if(activity_obj) {
            act_ext = lv_obj_get_ext_attr(activity_obj);
            LV_ASSERT_MEM(act_ext);
            break;
        }
    }
    if(activity_obj) {
        if(ACT_ID_SPEECH_RECOG_SPEAK == act_id[i]) {
            printf("%s: SPEECH_RECOG_SPEAK\n", __FUNCTION__);
            if(ext->buffer) {
                uint32_t duration_ms;
                uint32_t buffer_size;
#ifndef BUILD_IN_PC_SIMULATOR
                Hal_Record_Buffer_Stop_Req(&buffer_size, &duration_ms);
#else /*for pc test*/
                Hal_Record_Buffer_Stop_Req_1(&buffer_size, &duration_ms);
#endif
                lv_mem_free(ext->buffer);
                ext->buffer = NULL;
            }
        } else if(ACT_ID_SPEECH_RECOG_AUDIO == act_id[i]) {
            printf("%s: SPEECH_RECOG_AUDIO\n", __FUNCTION__);
            lv_obj_t * obj = NULL;
            lv_watch_get_child_obj(activity_obj, lv_watch_obj_signal, &obj);
            LV_ASSERT_MEM(obj);
            lv_speech_recog_audio_ext_t * obj_ext = lv_obj_get_ext_attr(obj);
            LV_ASSERT_MEM(obj_ext);
            if(obj_ext->bar_task) {
                lv_task_del(obj_ext->bar_task);
                obj_ext->bar_task = NULL;
                app_adaptor_speech_recog_stop_audio_req(obj_ext->audio_index);
            }
        } else if(ACT_ID_SPEECH_RECOG_SEND == act_id[i]) {
            printf("%s: SPEECH_RECOG_SEND\n", __FUNCTION__);
        }
        speech_recog_del_interface(act_id[i]);
    }

    if(ext) {
        if(ext->voice_data) {
            Hal_Tone_Play_End();
            lv_mem_free(ext->voice_data);
            ext->voice_data = NULL;
        }
    }
}

#if 0
void speech_recog_alarm_ind(void)
{
    speech_recog_mt_call_ind();
}
#endif

/**********************
 *   STATIC FUNCTIONS
 **********************/
static void speech_recog_set_user_num(lv_obj_t * obj, uint32_t user_num)
{
    lv_obj_user_data_t * user_data = lv_obj_get_user_data_ptr(obj);
    user_data->user_num = user_num;
}

static void speech_recog_set_user_ptr(lv_obj_t * obj, void * user_ptr)
{
    lv_obj_user_data_t * user_data = lv_obj_get_user_data_ptr(obj);
    user_data->user_data = user_ptr;
}

static uint32_t speech_recog_get_user_num(lv_obj_t * obj)
{
    lv_obj_user_data_t * user_data = lv_obj_get_user_data_ptr(obj);
    return user_data->user_num;
}

static void * speech_recog_get_user_ptr(lv_obj_t * obj)
{
    lv_obj_user_data_t * user_data = lv_obj_get_user_data_ptr(obj);
    return user_data->user_data;
}

static void speech_recog_send_end_anim(void * para)
{
    speech_recog_del_interface(ACT_ID_SPEECH_RECOG_SEND);
}

static void speech_recog_refreshing_anim(lv_anim_t * anim)
{
    lv_obj_t * img = (lv_obj_t *)anim->var;
    uint8_t step = speech_recog_get_user_num(img);
    switch(step) {
        case 1:
            lv_img_set_src(img, ICON_REFRESHING2);
            speech_recog_set_user_num(img, 2);
            break;
        case 2:
            lv_img_set_src(img, ICON_REFRESHING3);
            speech_recog_set_user_num(img, 3);
            break;
        case 3:
            lv_img_set_src(img, ICON_REFRESHING4);
            speech_recog_set_user_num(img, 4);
            break;
        case 4:
            lv_img_set_src(img, ICON_REFRESHING5);
            speech_recog_set_user_num(img, 5);
            break;
        case 5:
            lv_img_set_src(img, ICON_REFRESHING6);
            speech_recog_set_user_num(img, 6);
            break;
        case 6:
            lv_img_set_src(img, ICON_REFRESHING7);
            speech_recog_set_user_num(img, 7);
            break;
        case 7:
            lv_img_set_src(img, ICON_REFRESHING8);
            speech_recog_set_user_num(img, 8);
            break;
        case 8:
            lv_img_set_src(img, ICON_REFRESHING1);
            speech_recog_set_user_num(img, 1);
            break;
        default:
            break;
    }
}

static void speech_recog_audio_anim_cb(lv_task_t * task)
{
    if(NULL == task) return;

    lv_speech_recog_audio_ext_t * ext = (lv_speech_recog_audio_ext_t *)task->user_data;

    int16_t value = lv_bar_get_value(ext->bar) + 1;
    lv_bar_set_value(ext->bar, value, LV_ANIM_OFF);

    char time[6] = {0};
    uint8_t min = value / 60;
    uint8_t sec = value % 60;
    snprintf(time, 6, "%02d:%02d", min, sec);
    lv_label_set_text(ext->label_time, time);

    if(value == ext->cur_max_value) {
        lv_task_del(ext->bar_task);
        ext->bar_task = NULL;

        uint16_t max_value = lv_bar_get_max_value(ext->bar);
        if(value < max_value) {
            lv_img_set_src(ext->img, ICON_REFRESHING1);
            lv_obj_t * cont_bg = lv_obj_get_parent(ext->img);
            lv_obj_align(ext->img, cont_bg, LV_ALIGN_IN_BOTTOM_MID, 0, -20);
            lv_obj_set_click(ext->img, false);
            speech_recog_set_user_num(ext->img, 1);

            lv_anim_path_t path;
            lv_anim_path_init(&path);
            lv_anim_path_set_cb(&path, lv_anim_path_step);
            lv_anim_t a = {};
            lv_anim_init(&a);
            lv_anim_set_var(&a, ext->img);
            lv_anim_set_start_cb(&a, (lv_anim_ready_cb_t)speech_recog_refreshing_anim);
            lv_anim_set_path(&a, &path);
            lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
            lv_anim_set_repeat_delay(&a, 1000);
            lv_anim_start(&a);
        } else {
            watch_set_sleep_lcd_only(false);
        }
    }
}

static void speech_recog_voice_over_cb(void * para)
{
    printf("%s\n", __FUNCTION__);

    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) return;

    if(ext->voice_data) {
        lv_mem_free(ext->voice_data);
        ext->voice_data = NULL;
    }
}

static lv_obj_t * speech_recog_get_obj(lv_watch_Activity_Id_t act_id)
{
    lv_obj_t * activity_obj = lv_watch_get_activity_obj(act_id);
    if(NULL == activity_obj) return NULL;

    lv_obj_t * obj = NULL;
    lv_watch_get_child_obj(activity_obj, lv_watch_obj_signal, &obj);
    return obj;
}

static void * speech_recog_get_ext(lv_watch_Activity_Id_t act_id)
{
    lv_obj_t * obj = speech_recog_get_obj(act_id);
    if(NULL == obj) return NULL;

    if(obj) {
        void * ext = lv_obj_get_ext_attr(obj);
        return ext;
    }
    return NULL;
}

static lv_res_t speech_recog_del_interface(lv_watch_Activity_Id_t act_id)
{
    lv_obj_t * activity_obj = lv_watch_get_activity_obj(act_id);
    if(NULL == activity_obj) return LV_RES_INV;

    lv_watch_activity_ext_t * ext = lv_obj_get_ext_attr(activity_obj);
    if(NULL == ext) return LV_RES_INV;
    if(ext->prepare_destory) {
        ext->prepare_destory(activity_obj);
    }
    lv_obj_del(activity_obj);

    return LV_RES_OK;
}

static void speech_recog_common_prepare_destroy(lv_obj_t * activity_obj)
{
    printf("%s\n", __FUNCTION__);

    lv_watch_png_cache_all_free();
}

static void * speech_recog_get_obj_ext(lv_obj_t * activity_obj)
{
    if(NULL == activity_obj) return NULL;

    lv_obj_t * obj = NULL;
    lv_watch_get_child_obj(activity_obj, lv_watch_obj_signal, &obj);
    if(NULL == obj) return NULL;

    void * ext = lv_obj_get_ext_attr(obj);

    return ext;
}

static void speech_recog_prepare_destroy(lv_obj_t * activity_obj)
{
    printf("%s: activity_obj %p\n", __FUNCTION__, activity_obj);

    if(NULL == activity_obj) return;

    lv_watch_png_cache_all_free();

    lv_obj_t * obj = NULL;
    lv_watch_get_child_obj(activity_obj, lv_watch_obj_signal, &obj);
    if(NULL == obj) return;

    lv_speech_recog_ext_t * ext = speech_recog_get_obj_ext(activity_obj);
    if(NULL == ext) return;
    if(NULL == ext->page) return;

    lv_style_reset(&(ext->style_txt_from_other));
    lv_style_reset(&(ext->style_txt_from_self));
    lv_style_reset(&(ext->style_cont_msg));

    if(ext->voice_data) {
        Hal_Tone_Play_End();
        lv_mem_free(ext->voice_data);
        ext->voice_data = NULL;
    }

    if(ext->buffer) {
        lv_mem_free(ext->buffer);
        ext->buffer = NULL;
    }

    lv_obj_t * scrl = lv_page_get_scrl(ext->page);
    lv_obj_t * cont = _lv_ll_get_head(&scrl->child_ll);
    while(NULL != cont) {
        lv_obj_t * label_chat = lv_obj_get_child_back(cont, NULL);
        while(label_chat) {
            if(speech_recog_get_user_num(label_chat)) {
                void * text = speech_recog_get_user_ptr(label_chat);
                printf("%s: cont %p, label_chat %p, text %p\n",
                       __FUNCTION__, cont, label_chat, text);
                lv_mem_free(text);
                speech_recog_set_user_num(label_chat, 0);
                break;
            }
            label_chat = lv_obj_get_child_back(cont, label_chat);
        }
        cont = _lv_ll_get_next(&scrl->child_ll, cont);
    }
    Hal_Audio_Manage_End_Ind(AUDIO_CTRL_PRIORITY_4);
#if 0
    /*inform voice msg of the end*/
     voice_msg_speech_recog_end();
#endif
}

static void speech_recog_detail_prepare_destroy(lv_obj_t * activity_obj)
{
    printf("%s: activity_obj %p\n", __FUNCTION__, activity_obj);

    lv_watch_png_cache_all_free();

    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) return;
    if(ext->voice_data) {
        Hal_Tone_Play_End();
        lv_mem_free(ext->voice_data);
        ext->voice_data = NULL;
    }

    lv_speech_recog_detail_ext_t * detail_ext = speech_recog_get_obj_ext(activity_obj);
    if(NULL == detail_ext) return;
    speech_recog_text_t * page_text = _lv_ll_get_head(&detail_ext->page_text);
    while(page_text) {
        lv_mem_free(page_text->text);
        page_text = _lv_ll_get_next(&detail_ext->page_text, page_text);
    }
    _lv_ll_clear(&detail_ext->page_text);
}

static void speech_recog_img_back_event_cb(lv_obj_t * img, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_obj_t * obj = lv_obj_get_parent(img);
        while(obj) {
            lv_obj_t * par = lv_obj_get_parent(obj);
            if(lv_scr_act() == par) {
                break;
            }
            obj = par;
        }
        printf("%s: act obj %p\n", __FUNCTION__, obj);
        if(NULL == obj) return;
        lv_watch_activity_ext_t * act_ext = lv_obj_get_ext_attr(obj);
        if(NULL == act_ext) return;
        if(act_ext->prepare_destory) {
            act_ext->prepare_destory(obj);
        }
        lv_obj_del(obj);
    }
}

static void speech_recog_img_prev_event_cb(lv_obj_t * img, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_speech_recog_detail_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG_DETAIL);
        printf("%s: ext %p\n", __FUNCTION__, ext);
        if(NULL == ext) return;
        speech_recog_text_t * prev_page_text = _lv_ll_get_prev(&ext->page_text, ext->cur_page_text);
        lv_label_set_text(ext->label, prev_page_text->text);
        lv_obj_t * cont_bg = lv_obj_get_parent(ext->label);
        lv_obj_align(ext->label, cont_bg, LV_ALIGN_IN_TOP_MID, 0, ext->interval);
        ext->cur_page_text = prev_page_text;
        if(NULL == _lv_ll_get_prev(&ext->page_text, prev_page_text)) {
            lv_obj_del(ext->img_prev);
            ext->img_prev = NULL;
        }
        if(NULL == ext->img_next) {
            ext->img_next = lv_img_create(cont_bg, NULL);
            lv_img_set_src(ext->img_next, ICON_SPEECH_NEXT);
            if(LV_BIDI_DIR_RTL == lv_obj_get_base_dir(cont_bg)) {
                lv_img_set_angle(ext->img_next, 1800);
                lv_obj_align(ext->img_next, cont_bg, LV_ALIGN_IN_BOTTOM_LEFT, 4, -10);
            } else {
                lv_obj_align(ext->img_next, cont_bg, LV_ALIGN_IN_BOTTOM_RIGHT, -4, -10);
            }
            lv_obj_set_click(ext->img_next, true);
            lv_obj_set_event_cb(ext->img_next, speech_recog_img_next_event_cb);
            lv_obj_set_adv_hittest(ext->img_next, false);
            lv_watch_obj_add_element(ext->img_next);
        }
    }
}

static void speech_recog_img_next_event_cb(lv_obj_t * img, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_speech_recog_detail_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG_DETAIL);
        printf("%s: ext %p\n", __FUNCTION__, ext);
        if(NULL == ext) return;
        speech_recog_text_t * next_page_text = _lv_ll_get_next(&ext->page_text, ext->cur_page_text);
        lv_label_set_text(ext->label, next_page_text->text);
        lv_obj_t * cont_bg = lv_obj_get_parent(ext->label);
        lv_obj_align(ext->label, cont_bg, LV_ALIGN_IN_TOP_MID, 0, ext->interval);
        ext->cur_page_text = next_page_text;
        if(NULL == _lv_ll_get_next(&ext->page_text, next_page_text)) {
            lv_obj_del(ext->img_next);
            ext->img_next = NULL;
        }
        if(NULL == ext->img_prev) {
            ext->img_prev = lv_img_create(cont_bg, NULL);
            lv_img_set_src(ext->img_prev, ICON_SPEECH_PREV);
            if(LV_BIDI_DIR_RTL == lv_obj_get_base_dir(cont_bg)) {
                lv_img_set_angle(ext->img_prev, 1800);
                lv_obj_align(ext->img_prev, cont_bg, LV_ALIGN_IN_BOTTOM_RIGHT, -4, -10);
            } else {
                lv_obj_align(ext->img_prev, cont_bg, LV_ALIGN_IN_BOTTOM_LEFT, 4, -10);
            }
            lv_obj_set_click(ext->img_prev, true);
            lv_obj_set_event_cb(ext->img_prev, speech_recog_img_prev_event_cb);
            lv_obj_set_adv_hittest(ext->img_prev, false);
            lv_watch_obj_add_element(ext->img_prev);
        }
    }
}

static uint32_t speech_recog_get_next_line(char * text,
        const lv_font_t * font,
        lv_coord_t letter_space,
        lv_coord_t max_width)
{
    lv_coord_t width = 0;
    uint32_t letter;
    uint32_t letter_next;
    uint32_t i = 0;
    uint32_t j;
    uint32_t last_i = 0;
    lv_coord_t char_width;
    uint32_t length = strlen(text);
    while(length > i) {
        letter = _lv_txt_encoded_next(text, &i);
        j = i;
        letter_next = _lv_txt_encoded_next(text, &j);
        char_width = lv_font_get_glyph_width(font, letter, letter_next);
        if(0 < char_width) {
            width += char_width;
            if(max_width < width) {
                break;
            }
            width += letter_space;
        }
        last_i = i;
    }

    return last_i;
}

static lv_obj_t * speech_recog_create_backgroud(lv_obj_t * par, lv_color_t color)
{
    lv_obj_t * cont_bg = lv_cont_create(par, NULL);
    LV_ASSERT_MEM(cont_bg);
    lv_obj_set_size(cont_bg, lv_obj_get_width(par), lv_obj_get_height(par));
    lv_obj_set_style_local_bg_color(cont_bg, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, color);
    lv_obj_set_click(cont_bg, false);
    lv_obj_align(cont_bg, par, LV_ALIGN_CENTER, 0, 0);

    return cont_bg;
}

static lv_obj_t * speech_recog_detail_create(char * text)
{
    if(NULL == text) return NULL;

    lv_watch_activity_ext_t activity_ext;
    memset(&activity_ext, 0, sizeof(lv_watch_activity_ext_t));
    activity_ext.actId = ACT_ID_SPEECH_RECOG_DETAIL;
    activity_ext.create = NULL;
    activity_ext.prepare_destory = speech_recog_detail_prepare_destroy;
    lv_obj_t * activity_obj = lv_watch_creat_activity_obj(&activity_ext);
    LV_ASSERT_MEM(activity_obj);

    printf("%s: activity_obj %p\n", __FUNCTION__, activity_obj);

    lv_obj_t * obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);
    lv_speech_recog_detail_ext_t * ext = lv_obj_allocate_ext_attr(obj, sizeof(lv_speech_recog_detail_ext_t));
    LV_ASSERT_MEM(ext);
    printf("%s: ext %p\n", __FUNCTION__, ext);
    _lv_ll_init(&ext->page_text, sizeof(speech_recog_text_t));
    ext->img_next = NULL;
    ext->img_prev = NULL;
    ext->interval = 30;

    lv_coord_t width_obj = lv_obj_get_width(obj);
    lv_coord_t height_obj = lv_obj_get_height(obj);

    lv_obj_t * cont_bg = speech_recog_create_backgroud(obj, LV_COLOR_MAKE(182, 247, 255));
    lv_watch_obj_add_element(cont_bg);

    lv_obj_t * img_close = lv_img_create(cont_bg, NULL);
    lv_img_set_src(img_close, ICON_SPEECH_CLOSE);
    lv_obj_align(img_close, cont_bg, LV_ALIGN_IN_BOTTOM_MID, 0, -10);
    lv_obj_set_click(img_close, true);
    lv_obj_set_event_cb(img_close, speech_recog_img_back_event_cb);
    lv_obj_set_adv_hittest(img_close, false);
    lv_watch_obj_add_element(img_close);

    ext->label = lv_label_create(cont_bg, NULL);
    lv_obj_add_style(ext->label, LV_LABEL_PART_MAIN, &lv_watch_font20_black);
    lv_coord_t max_width_txt = width_obj - 50;
    lv_coord_t max_height_txt = height_obj - lv_obj_get_height(img_close) - 8 - 30;
    const lv_font_t * font = lv_obj_get_style_text_font(ext->label, LV_STATE_DEFAULT);
    lv_obj_set_size(ext->label, max_width_txt, max_height_txt);
    uint8_t max_line = max_height_txt / lv_font_get_line_height(font);
    uint8_t * char_number = lv_mem_alloc(max_line);
    uint32_t length_txt = strlen(text);
    uint32_t total_length = 0;
    uint32_t start_index = 0;
    speech_recog_text_t * cur_page_text;
    lv_coord_t text_letter_space = lv_obj_get_style_text_letter_space(ext->label,
                                                                      LV_STATE_DEFAULT);
    printf("%s: text_letter_space %d\n", __FUNCTION__, text_letter_space);
    while(length_txt > total_length) {
        memset(char_number, 0, max_line);
        start_index = total_length;
        uint8_t i = 0;
        for(; i < max_line; i++) {
            char_number[i]
                = speech_recog_get_next_line(&text[total_length],
                                             font,
                                             text_letter_space,
                                             max_width_txt);
            total_length += char_number[i];
            if(length_txt <= total_length) {
                i++;
                break;
            }
        }
        cur_page_text = _lv_ll_ins_tail(&ext->page_text);
        cur_page_text->text = (char *)lv_mem_alloc(total_length - start_index + i);
        uint32_t pos = 0;
        for(uint8_t j = 0; j < i; j++) {
            memcpy(&cur_page_text->text[pos + j], &text[pos + start_index], char_number[j] + 1);
            pos += char_number[j];
            if(j == (i - 1)) {
                cur_page_text->text[pos + j] = '\0';
            } else {
                cur_page_text->text[pos + j] = '\n';
            }
        }
    }
    lv_mem_free(char_number);

    cur_page_text = _lv_ll_get_head(&ext->page_text);
    lv_label_set_text(ext->label, cur_page_text->text);
    lv_obj_align(ext->label, cont_bg, LV_ALIGN_IN_TOP_MID, 0, ext->interval);
    ext->cur_page_text = cur_page_text;

    if(_lv_ll_get_next(&ext->page_text, cur_page_text)) {
        ext->img_next = lv_img_create(cont_bg, NULL);
        lv_img_set_src(ext->img_next, ICON_SPEECH_NEXT);
        if(LV_BIDI_DIR_RTL == lv_obj_get_base_dir(cont_bg)) {
            lv_img_set_angle(ext->img_next, 1800);
            lv_obj_align(ext->img_next, cont_bg, LV_ALIGN_IN_BOTTOM_LEFT, 4, -10);
        } else {
            lv_obj_align(ext->img_next, cont_bg, LV_ALIGN_IN_BOTTOM_RIGHT, -4, -10);
        }
        lv_obj_set_click(ext->img_next, true);
        lv_obj_set_event_cb(ext->img_next, speech_recog_img_next_event_cb);
        lv_obj_set_adv_hittest(ext->img_next, false);
        lv_watch_obj_add_element(ext->img_next);
    }

    return obj;
}

static void speech_recog_text_detail_event_cb(lv_obj_t * cont, lv_event_t e)
{
    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) return;

    if(LV_EVENT_PRESSED == e) {
        ext->pressing = true;
    } else if(LV_EVENT_CLICKED == e) {
        if(true == ext->pressing) {
            ext->pressing = false;

            lv_obj_t * label_chat = lv_obj_get_child_back(cont, NULL);
            void * text = speech_recog_get_user_ptr(label_chat);
            if(NULL == text) return;
            lv_obj_t * obj = speech_recog_detail_create((char *)text);
            LV_ASSERT_MEM(obj);
        }
    }
}

static void speech_recog_audio_prepare_destroy(lv_obj_t * activity_obj)
{
    printf("%s: activity_obj %p\n", __FUNCTION__, activity_obj);

    lv_speech_recog_audio_ext_t * ext = speech_recog_get_obj_ext(activity_obj);
    if(NULL == ext) return;

    if(ext->bar_task) {
        lv_task_del(ext->bar_task);
    }
    app_adaptor_speech_recog_stop_audio_req(ext->audio_index);

    watch_set_sleep_lcd_only(false);

    lv_watch_png_cache_all_free();
}

static lv_obj_t * speech_recog_audio_create(char * text, uint8_t audio_index)
{
    if(NULL == text) return NULL;

    lv_watch_activity_ext_t activity_ext;
    memset(&activity_ext, 0, sizeof(lv_watch_activity_ext_t));
    activity_ext.actId = ACT_ID_SPEECH_RECOG_AUDIO;
    activity_ext.create = NULL;
    activity_ext.prepare_destory = speech_recog_audio_prepare_destroy;
    lv_obj_t * activity_obj = lv_watch_creat_activity_obj(&activity_ext);
    LV_ASSERT_MEM(activity_obj);

    printf("%s: index %d, activity_obj %p\n", __FUNCTION__, audio_index, activity_obj);

    lv_obj_t * obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);
    lv_speech_recog_audio_ext_t * ext = lv_obj_allocate_ext_attr(obj, sizeof(lv_speech_recog_audio_ext_t));
    LV_ASSERT_MEM(ext);
    ext->audio_index = audio_index;
    ext->bar_task = NULL;

    lv_obj_t * cont_bg = speech_recog_create_backgroud(obj, LV_COLOR_MAKE(182, 247, 255));

    lv_obj_t * label = lv_label_create(cont_bg, NULL);
    lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20_black);
    const lv_font_t * font = lv_obj_get_style_text_font(label, LV_STATE_DEFAULT);
    lv_coord_t width_label = lv_obj_get_width(cont_bg) - 50;
    lv_coord_t height_label = lv_obj_get_height(cont_bg) / 2;
    lv_obj_set_size(label, width_label, height_label);
    uint8_t max_line = SPEECH_RECOG_MAX_AUDIO_LINE_NUM;
    uint8_t char_number[SPEECH_RECOG_MAX_AUDIO_LINE_NUM] = {0};
    uint32_t length_txt = strlen(text);
    uint32_t total_length = 0;
    char * new_text = (char *)lv_mem_alloc(length_txt + max_line);
    memset(new_text, 0, length_txt + max_line);
    for(uint8_t i = 0; i < max_line; i++) {
        char_number[i]
            = speech_recog_get_next_line(&text[total_length],
                                         font,
                                         lv_obj_get_style_text_letter_space(label,
                                                                            LV_STATE_DEFAULT),
                                         width_label);
        memcpy(&new_text[total_length + i], &text[total_length], char_number[i]);
        total_length += char_number[i];
        if(length_txt <= total_length) {
            break;
        }
        new_text[total_length + i] = '\n';
    }
    lv_label_set_text(label, new_text);
    lv_mem_free(new_text);
    lv_obj_align(label, cont_bg, LV_ALIGN_IN_TOP_MID, 0, 25);

    ext->img = lv_img_create(cont_bg, NULL);
    lv_img_set_src(ext->img, ICON_REFRESHING1);
    lv_obj_align(ext->img, cont_bg, LV_ALIGN_IN_BOTTOM_MID, 0, -20);
    speech_recog_set_user_num(ext->img, 1);

    watch_set_sleep_lcd_only(true);

    lv_anim_path_t path;
    lv_anim_path_init(&path);
    lv_anim_path_set_cb(&path, lv_anim_path_step);
    lv_anim_t a = {};
    lv_anim_init(&a);
    lv_anim_set_var(&a, ext->img);
    lv_anim_set_start_cb(&a, (lv_anim_ready_cb_t)speech_recog_refreshing_anim);
    lv_anim_set_path(&a, &path);
    lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
    lv_anim_set_repeat_delay(&a, 1000);
    lv_anim_start(&a);

    app_adaptor_speech_recog_play_audio_req(audio_index);

    return obj;
}

static void speech_recog_play_audio_event_cb(lv_obj_t * cont, lv_event_t e)
{
    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) return;

    if(LV_EVENT_PRESSED == e) {
        ext->pressing = true;
    } else if(LV_EVENT_CLICKED == e) {
        if(true == ext->pressing) {
            ext->pressing = false;

            lv_obj_t * label_chat = lv_obj_get_child_back(cont, NULL);
            char * text = speech_recog_get_user_ptr(label_chat);
            if(NULL == text) return;
            uint8_t audio_index = speech_recog_get_user_num(lv_obj_get_child(cont, NULL));
            lv_obj_t * obj = speech_recog_audio_create(text, audio_index);
            LV_ASSERT_MEM(obj);
        }
    }
}

static void speech_recog_add_msg(lv_speech_recog_ext_t * ext,
                                 char * text,
                                 speech_recog_msg_src_t src,
                                 speech_recog_msg_type_t type,
                                 uint8_t audio_index)
{
    printf("%s: type %d, src %d, audio_index %d\n",
           __FUNCTION__, type, src, audio_index);

    if(NULL == text) return;

    lv_obj_t * cont = lv_cont_create(ext->page, NULL);
    lv_obj_add_style(cont, LV_CONT_PART_MAIN, &ext->style_cont_msg);
    lv_cont_set_fit(cont, true);
    lv_obj_set_click(cont, false);
    speech_recog_set_user_num(cont, type);

    lv_obj_t * label_chat = lv_label_create(cont, NULL);
    lv_obj_add_style(label_chat, LV_LABEL_PART_MAIN, &lv_watch_font20_black);
    lv_coord_t width_one_line;
    uint8_t max_row_num;
    const char * detail = lv_lang_get_text(WATCH_TEXT_ID_DETAIL);
    lv_coord_t width_offset;
    lv_coord_t width_detail = 0;
    lv_font_t * font = (lv_font_t *)lv_obj_get_style_text_font(label_chat, LV_STATE_DEFAULT);
    if(SPEECH_RECOG_MSG_TYPE_TEXT == type) {
        width_one_line = LV_HOR_RES * 3 / 4;
        max_row_num = SPEECH_RECOG_MAX_TEXT_LINE_NUM;
        if(SPEECH_RECOG_MSG_FROM_SERVER == src) {
            width_detail
                = _lv_txt_get_width(detail, strlen(detail), font, 0, LV_TXT_FLAG_NONE);
            width_offset = width_detail + ext->width_omit;
        } else {
            width_offset = ext->width_omit;
        }
    } else {
        width_one_line = LV_HOR_RES / 2;
        max_row_num = SPEECH_RECOG_MAX_AUDIO_TEXT_LINE_NUM;
        width_offset = ext->width_omit;
    }

    /*add "..." for audio text or "...detail" for text at the last row if row_number > max_row_num*/
    uint32_t max_last_row_width = width_one_line - width_offset;

    uint8_t row_number = 1;
    lv_coord_t width = 0;
    lv_coord_t new_width;
    lv_coord_t char_width;
    uint32_t length = strlen(text);
    uint32_t letter;
    uint32_t letter_next;
    uint32_t i = 0;
    uint32_t j;
    uint32_t last_char_i[SPEECH_RECOG_MAX_LINE_NUM] = {0};
    uint32_t last_i = 0;
    uint32_t temp_last_i = 0;
    while(length > i) {
        letter = _lv_txt_encoded_next(text, &i);
        j = i;
        letter_next = _lv_txt_encoded_next(text, &j);
        char_width = lv_font_get_glyph_width(font, letter, letter_next);
        new_width = width + char_width;
        if((max_row_num == row_number)
                && (0 == temp_last_i)
                && (max_last_row_width < new_width)) {
            temp_last_i = last_i;
        }
        if(width_one_line < new_width) {
            if(max_row_num == row_number) {
                if(0 < temp_last_i) {
                    last_char_i[row_number - 1] = temp_last_i;
                }
                row_number++;
                break;
            }
            if(0 < char_width) {
                width = char_width;
            } else {
                width = 0;
            }
            last_char_i[row_number - 1] = last_i;
            last_char_i[row_number] = i;
            row_number++;
        } else {
            last_char_i[row_number - 1] = i;
            width = new_width;
        }
        last_i = i;
    }
    if(1 < row_number) {
        char * new_text = (char *)lv_mem_alloc(length + max_row_num);
        memset(new_text, 0, length + max_row_num);
        memcpy(new_text, text, last_char_i[0]);
        uint8_t real_row_num = (max_row_num > row_number) ? row_number : max_row_num;
        for(i = 1; i < real_row_num; i++) {
            new_text[last_char_i[i - 1] + i - 1] = '\n';
            memcpy(&new_text[last_char_i[i - 1] + i],
                   &text[last_char_i[i - 1]],
                   last_char_i[i] - last_char_i[i - 1]);
        }
        if(max_row_num < row_number) {
            memcpy(&new_text[last_char_i[max_row_num - 1] + max_row_num - 1], "...", 4);
        }
        lv_label_set_text(label_chat, new_text);
        lv_mem_free(new_text);
    } else {
        lv_label_set_text(label_chat, text);
    }

    lv_bidi_dir_t dir = lv_obj_get_base_dir(cont);

    speech_recog_set_user_num(label_chat, 0);
    if((SPEECH_RECOG_MSG_TYPE_TEXT == type)
            && (SPEECH_RECOG_MSG_FROM_SERVER == src)) {
        if(max_row_num < row_number) {
            lv_obj_t * label_detail = lv_label_create(cont, NULL);
            lv_obj_set_style_local_text_font(label_detail,
                                             LV_LABEL_PART_MAIN,
                                             LV_STATE_DEFAULT,
                                             LV_THEME_WATCH_NIGHT_FONT_SMALL);
            lv_obj_set_style_local_text_color(label_detail,
                                             LV_LABEL_PART_MAIN,
                                             LV_STATE_DEFAULT,
                                              LV_COLOR_BLUE);
            lv_label_set_text(label_detail, detail);
            lv_coord_t height_detail = lv_obj_get_height(label_detail);
            lv_coord_t h_detail = lv_obj_get_y(label_chat)
                                  + lv_obj_get_height(label_chat)
                                  - height_detail
                                  + 1;
            if(LV_BIDI_DIR_RTL == dir) {
                lv_coord_t w_detail = lv_obj_get_width(cont) - lv_obj_get_x(label_chat) - width_detail;
                lv_obj_align(label_detail, cont, LV_ALIGN_IN_TOP_RIGHT, -w_detail, h_detail);
            } else {
                lv_coord_t w_detail = lv_obj_get_x(label_chat) + width_one_line - width_detail;
                lv_obj_align(label_detail, cont, LV_ALIGN_IN_TOP_LEFT, w_detail, h_detail);
            }
            lv_obj_set_click(cont, true);
            lv_obj_set_event_cb(cont, speech_recog_text_detail_event_cb);
            speech_recog_set_user_ptr(label_chat, text);
            speech_recog_set_user_num(label_chat, 1);
            printf("%s: cont %p, label_chat %p, text %p\n",
                   __FUNCTION__, cont, label_chat, text);
        } else {
            lv_mem_free(text);
        }
    } else if(SPEECH_RECOG_MSG_TYPE_AUDIO == type) {
        lv_obj_t * img_play = lv_img_create(cont, NULL);
        lv_img_set_src(img_play, ICON_AUDIO_PLAY);
        if(LV_BIDI_DIR_RTL == dir) {
            lv_img_set_angle(img_play, 1800);
            lv_obj_align(img_play, label_chat, LV_ALIGN_OUT_LEFT_MID, -4, 0);
        } else {
            lv_obj_align(img_play, label_chat, LV_ALIGN_OUT_RIGHT_MID, 4, 0);
        }
        lv_obj_set_click(cont, true);
        lv_obj_set_event_cb(cont, speech_recog_play_audio_event_cb);
        lv_obj_set_adv_hittest(img_play, false);
        speech_recog_set_user_num(img_play, audio_index);
        speech_recog_set_user_ptr(label_chat, text);
        speech_recog_set_user_num(label_chat, 1);
        printf("%s: cont %p, label_chat %p, text %p\n",
               __FUNCTION__, cont, label_chat, text);
    } else {
        lv_mem_free(text);
    }

    lv_obj_t * scrl = lv_page_get_scrl(ext->page);
    lv_coord_t height_scrl = lv_obj_get_height(scrl);
    lv_coord_t height_cont = lv_obj_get_height(cont);
    lv_coord_t new_height_scrl = height_scrl + height_cont + SPEECH_RECOG_MSG_SPACING;
    lv_obj_set_height(scrl, new_height_scrl);
    if(SPEECH_RECOG_MSG_FROM_SERVER == src) {
        lv_obj_align(cont, scrl, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
        lv_obj_add_style(cont, LV_CONT_PART_MAIN, &ext->style_txt_from_other);
    } else {
        lv_obj_align(cont, scrl, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
        lv_obj_add_style(cont, LV_CONT_PART_MAIN, &ext->style_txt_from_self);
    }

    lv_page_focus(ext->page, cont, 0);

    lv_page_glue_obj(cont, true);
    lv_watch_obj_add_element(cont);
}

static lv_obj_t * speech_recog_send_create(void)
{
    printf("%s\n", __FUNCTION__);

    lv_watch_activity_ext_t activity_ext;
    memset(&activity_ext, 0, sizeof(lv_watch_activity_ext_t));
    activity_ext.actId = ACT_ID_SPEECH_RECOG_SEND;
    activity_ext.create = NULL;
    activity_ext.prepare_destory = speech_recog_common_prepare_destroy;
    lv_obj_t * activity_obj = lv_watch_creat_activity_obj(&activity_ext);
    LV_ASSERT_MEM(activity_obj);

    lv_obj_t * obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);
    lv_speech_recog_send_ext_t * ext = lv_obj_allocate_ext_attr(obj, sizeof(lv_speech_recog_send_ext_t));
    LV_ASSERT_MEM(ext);

    ext->img = lv_img_create(obj, NULL);
    lv_img_set_src(ext->img, ICON_NET_SEARCHING);
    lv_obj_align(ext->img, obj, LV_ALIGN_CENTER, 0, 0);

    return obj;
}

static void speech_recog_record_error_task_cb(lv_task_t * task)
{
    printf("%s\n", __FUNCTION__);

    /*MCI_EVENT_ERROR*/
    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) return;

    if(ext->buffer) {
        lv_mem_free(ext->buffer);
        ext->buffer = NULL;
    }
    speech_recog_del_interface(ACT_ID_SPEECH_RECOG_SPEAK);
}

static void speech_recog_speak_record_cb(MCI_EVNET_T event, MCI_INFO_T info_type, int32_t value)
{
    if(MCI_EVENT_ERROR == event) {
        lv_task_t * record_error_task = lv_task_create(speech_recog_record_error_task_cb, 10, LV_TASK_PRIO_MID, NULL);
        lv_task_once(record_error_task);
    }
}

static lv_obj_t * speech_recog_speak_create(void)
{
    printf("%s\n", __FUNCTION__);

    lv_watch_activity_ext_t activity_ext;
    memset(&activity_ext, 0, sizeof(lv_watch_activity_ext_t));
    activity_ext.actId = ACT_ID_SPEECH_RECOG_SPEAK;
    activity_ext.create = NULL;
    activity_ext.prepare_destory = speech_recog_common_prepare_destroy;
    lv_obj_t * activity_obj = lv_watch_creat_activity_obj(&activity_ext);
    LV_ASSERT_MEM(activity_obj);

    lv_obj_t * obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);

    lv_obj_t * img_bg = lv_img_create(obj, NULL);
    lv_img_set_src(img_bg, ICON_RECORDING);
    lv_obj_align(img_bg, obj, LV_ALIGN_CENTER, 0, 0);

    lv_obj_t * img_back = lv_img_create(img_bg, NULL);
    lv_img_set_src(img_back, ICON_SPEECH_BACK);

    lv_obj_t * img_stop_speak = lv_img_create(img_bg, NULL);
    lv_img_set_src(img_stop_speak, ICON_BUTTON_NO_TOUCH);

    if(LV_BIDI_DIR_RTL == lv_obj_get_base_dir(obj)) {
        lv_obj_align(img_stop_speak, img_bg, LV_ALIGN_IN_BOTTOM_LEFT, 14, -8);
        lv_obj_align(img_back, img_bg, LV_ALIGN_IN_BOTTOM_RIGHT, -14, -8);
    } else {
        lv_obj_align(img_back, img_bg, LV_ALIGN_IN_BOTTOM_LEFT, 14, -8);
        lv_obj_align(img_stop_speak, img_bg, LV_ALIGN_IN_BOTTOM_RIGHT, -14, -8);
    }

    return obj;
}

static void speech_recog_speak_click_anim(void * para)
{
    if(NULL == para) return;

    lv_anim_t * a = (lv_anim_t *)para;
    lv_img_set_src(a->var, ICON_SPEECH_BUTTON);
}

static void speech_recog_speak_event_cb(lv_obj_t * img, lv_event_t e)
{
    if(LV_EVENT_RELEASED == e || LV_EVENT_PRESS_LOST == e) {
        if(lv_watch_get_activity_obj(ACT_ID_SPEECH_RECOG_SPEAK)) {
            lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
            if(NULL == ext) return;
            uint32_t buffer_size = 0;
            if(ext->buffer) {
                uint32_t duration_ms;
#ifndef BUILD_IN_PC_SIMULATOR
                Hal_Record_Buffer_Stop_Req(&buffer_size, &duration_ms);
#else /*for pc test*/
                Hal_Record_Buffer_Stop_Req_1(&buffer_size, &duration_ms);
#endif
                if(SPEECH_RECOG_AMR_HEAD_SIZE < buffer_size) {
                    app_adaptor_speech_recog_nw_search_req(ext->buffer, buffer_size);
                } else {
                    lv_mem_free(ext->buffer);
                }
                ext->buffer = NULL;
            }
            printf("%s: stop recording, buffer size %d\n", __FUNCTION__, buffer_size);
            speech_recog_del_interface(ACT_ID_SPEECH_RECOG_SPEAK);
            if(SPEECH_RECOG_AMR_HEAD_SIZE < buffer_size) {
                lv_obj_t * obj = speech_recog_send_create();
                LV_ASSERT_MEM(obj);
            }
        } else if(LV_EVENT_RELEASED == e) {
            printf("%s: please long touch spk\n", __FUNCTION__);
            lv_img_set_src(img, ICON_LONG_TOUCH_SPK);
            lv_anim_path_t path;
            lv_anim_path_init(&path);
            lv_anim_path_set_cb(&path, lv_anim_path_step);
            lv_anim_t a = {};
            lv_anim_init(&a);
            lv_anim_set_var(&a, img);
            lv_anim_set_ready_cb(&a, (lv_anim_ready_cb_t)speech_recog_speak_click_anim);
            lv_anim_set_time(&a, 2000);
            lv_anim_set_path(&a, &path);
            lv_anim_start(&a);
        }
    } else if(LV_EVENT_LONG_PRESSED == e) {
        lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
        if(NULL == ext) return;

        if(0 == ext->old_ext.element_click_en) {
            /*sliding to the right, not click button*/
            return;
        }

        printf("%s: start recording, voice data %p\n", __FUNCTION__, ext->voice_data);

        if(ext->voice_data) {
            Hal_Tone_Play_End();
            lv_mem_free(ext->voice_data);
            ext->voice_data = NULL;
        }

        lv_obj_t * obj = speech_recog_speak_create();
        LV_ASSERT_MEM(obj);

        ext->buffer = (uint8_t *)lv_mem_alloc(SPEECH_RECOG_MAX_RECORD_SIZE);
#ifndef BUILD_IN_PC_SIMULATOR
        Hal_Record_Buffer_Start_Req(ext->buffer,
                                    SPEECH_RECOG_MAX_RECORD_SIZE,
                                    SPEECH_RECOG_MAX_RECORD_DURATION * 1000,
                                    speech_recog_speak_record_cb);
#else /*for pc test*/
        Hal_Record_Buffer_Start_Req_1(ext->buffer,
                                      SPEECH_RECOG_MAX_RECORD_SIZE,
                                      SPEECH_RECOG_MAX_RECORD_DURATION * 1000,
                                      speech_recog_speak_record_cb);
#endif
    }
}

static lv_res_t speech_recog_page_scrl_signal(lv_obj_t * page_scrl, lv_signal_t sign, void * param)
{
    lv_res_t res;

    lv_speech_recog_ext_t * ext = speech_recog_get_ext(ACT_ID_SPEECH_RECOG);
    if(NULL == ext) return LV_RES_INV;

    /* Include the ancient signal function */
    res = ext->ancient_page_scrl_signal(page_scrl, sign, param);
    if(res != LV_RES_OK) return res;

    if(LV_SIGNAL_COORD_CHG == sign) {
        if(true == ext->pressing) {
            ext->pressing = false;
        }
    }

    return LV_RES_OK;
}

static void speech_recog_note_create(lv_obj_t * obj, uint16_t text_id)
{
    lv_obj_t * label = lv_label_create(obj, NULL);
    lv_obj_add_style(label, LV_OBJ_PART_MAIN, &lv_watch_font20);

    lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
    lv_obj_set_click(label, false);
    lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
    lv_obj_set_width(label, lv_obj_get_width(obj) - 50);
    lv_label_set_text_id(label, text_id);
    lv_obj_align(label, obj, LV_ALIGN_CENTER, 0, 0);
}

static lv_obj_t * speech_recog_create(lv_obj_t * activity_obj)
{
#if SPEECH_RECOG_TEST != 0
    test_num = 0;
#endif

    if(activity_obj == NULL) {
        lv_watch_activity_ext_t activity_ext;
        memset(&activity_ext, 0, sizeof(lv_watch_activity_ext_t));
        activity_ext.actId = ACT_ID_SPEECH_RECOG;
        activity_ext.create = speech_recog_create;
        activity_ext.prepare_destory = speech_recog_prepare_destroy;
        activity_obj = lv_watch_creat_activity_obj(&activity_ext);
        LV_ASSERT_MEM(activity_obj);
    }

    printf("%s: activity_obj %p\n", __FUNCTION__, activity_obj);
    Hal_Audio_Manage_Start_Req(AUDIO_CTRL_PRIORITY_4,speech_recog_audio_ctrl_callback);
    lv_obj_t * obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);
    lv_speech_recog_ext_t * ext = lv_obj_allocate_ext_attr(obj, sizeof(lv_speech_recog_ext_t));
    LV_ASSERT_MEM(ext);
    ext->page = NULL;
    ext->voice_data = NULL;
    ext->audio_num = 0;
    ext->buffer = NULL;

    if(setting_is_flying_mode()) {
        speech_recog_note_create(obj, WATCH_TEXT_ID_PLEASE_TURN_OFF_FLYING_MODE);
        return obj;
    }

    bool is_no_connetion = false;
    if((false == watch_modem_sim_present_check_req())
       || (MMI_MODEM_SIGNAL_BAR_0 == watch_modem_get_signal_bar_req())) {
        is_no_connetion = true;
    }
#if USE_LV_WLAN != 0
    if(is_no_connetion) {
        if(hal_wlan_is_connected_state()) {
            is_no_connetion = false;
        }
    }
#endif
    if(is_no_connetion) {
        speech_recog_note_create(obj, WATCH_TEXT_ID_NO_SIM_OR_NETWORK);
        return obj;
    }

    lv_obj_t * cont_bg = speech_recog_create_backgroud(obj, LV_COLOR_MAKE(182, 247, 255));
    lv_obj_t * img_back = lv_img_create(cont_bg, NULL);
    LV_ASSERT_MEM(img_back);
    lv_img_set_src(img_back, ICON_SPEECH_BACK);
    lv_obj_set_click(img_back, true);
    lv_obj_set_event_cb(img_back, speech_recog_img_back_event_cb);
    lv_obj_set_adv_hittest(img_back, false);
    lv_watch_obj_add_element(img_back);

    lv_obj_t * img_speak = lv_img_create(cont_bg, NULL);
    LV_ASSERT_MEM(img_speak);
    lv_img_set_src(img_speak, ICON_SPEECH_BUTTON);
    lv_obj_set_click(img_speak, true);
    lv_obj_set_event_cb(img_speak, speech_recog_speak_event_cb);
    lv_obj_set_adv_hittest(img_speak, false);
    lv_watch_obj_add_element(img_speak);

    if(LV_BIDI_DIR_RTL == lv_obj_get_base_dir(cont_bg)) {
        lv_obj_align(img_speak, cont_bg, LV_ALIGN_IN_BOTTOM_LEFT, 14, -8);
        lv_obj_align(img_back, cont_bg, LV_ALIGN_IN_BOTTOM_RIGHT, -14, -8);
    } else {
        lv_obj_align(img_back, cont_bg, LV_ALIGN_IN_BOTTOM_LEFT, 14, -8);
        lv_obj_align(img_speak, cont_bg, LV_ALIGN_IN_BOTTOM_RIGHT, -14, -8);
    }

    ext->page = lv_page_create(cont_bg, NULL);
    lv_coord_t width_obj = lv_obj_get_width(obj);
    lv_coord_t height_obj = lv_obj_get_height(obj);
    lv_coord_t height_page = height_obj - lv_obj_get_height(img_back) - 24;
    lv_obj_set_size(ext->page, width_obj - 20, height_page);
    lv_obj_align(ext->page, cont_bg, LV_ALIGN_IN_TOP_MID, 0, 10);
    lv_obj_add_style(ext->page, LV_PAGE_PART_BG, &lv_watch_style_transp);
    lv_obj_add_style(ext->page, LV_PAGE_PART_SCROLLABLE, &lv_watch_style_transp);
    lv_obj_add_style(ext->page, LV_PAGE_PART_SCROLLBAR, &lv_watch_style_transp);
    lv_page_set_scrollable_fit(ext->page, LV_FIT_NONE);
    lv_obj_t * page_scrl = lv_page_get_scrl(ext->page);
    ext->ancient_page_scrl_signal = lv_obj_get_signal_cb(page_scrl);
    lv_obj_set_signal_cb(page_scrl, speech_recog_page_scrl_signal);
    lv_obj_set_height(page_scrl, 0);
    lv_watch_obj_add_element(ext->page);

    lv_style_init(&ext->style_cont_msg);
    lv_style_copy(&ext->style_cont_msg, &lv_style_pretty);
    lv_style_set_pad_left(&ext->style_cont_msg, LV_STATE_DEFAULT, 10);
    lv_style_set_pad_right(&ext->style_cont_msg, LV_STATE_DEFAULT, 10);
    lv_style_set_pad_top(&ext->style_cont_msg, LV_STATE_DEFAULT, 10);
    lv_style_set_pad_bottom(&ext->style_cont_msg, LV_STATE_DEFAULT, 10);

    lv_style_init(&ext->style_txt_from_other);
    lv_style_copy(&ext->style_txt_from_other, &ext->style_cont_msg);
    lv_style_set_bg_color(&ext->style_txt_from_other, LV_STATE_DEFAULT, LV_COLOR_MAKE(255, 239, 130));

    lv_style_init(&ext->style_txt_from_self);
    lv_style_copy(&ext->style_txt_from_self, &ext->style_cont_msg);
    lv_style_set_bg_color(&ext->style_txt_from_self, LV_STATE_DEFAULT, LV_COLOR_MAKE(255, 225, 225));

    char omit[] = {"..."};
    ext->width_omit = _lv_txt_get_width(omit,
                                        strlen(omit),
                                        LV_THEME_WATCH_NIGHT_FONT_SMALL,
                                        0,
                                        LV_TXT_FLAG_NONE);
    const char * hello = lv_lang_get_text(WATCH_TEXT_ID_HELLO_CHAT);
    char * text = (char *)lv_mem_alloc(strlen(hello) + 1);
    memcpy(text, hello, strlen(hello) + 1);
    speech_recog_add_msg(ext, text, SPEECH_RECOG_MSG_FROM_SERVER, SPEECH_RECOG_MSG_TYPE_TEXT, 0);

    return obj;
}

#if SPEECH_RECOG_TEST != 0
LV_AUDIO_DECLARE(audio_power_on);
static void speech_recog_test_task_cb(lv_task_t * task)
{
    test_num++;
    printf("%s: test_num %d\n", __FUNCTION__, test_num);
    if(1 == test_num) {
        char str[] = {"Tell a joke"};
        char * text = (char *)lv_mem_alloc(strlen(str) + 1);
        memcpy(text, str, strlen(str) + 1);
        app_adaptor_speech_recog_nw_search_cnf(text);
        char new_text[] = {"abcdefghijklmnopqrstuvwxyz"};
        uint16_t text_len = strlen(new_text) * 6 + 1;
        text = (char *)lv_mem_alloc(text_len);
        snprintf(text, text_len, "%s%s%s%s%s%s",
                 new_text, new_text, new_text, new_text, new_text, new_text);
#if 0   // for audio data buffer
        uint32_t voice_size = audio_power_on.data_size;
        uint8_t * voice_data = lv_mem_alloc(voice_size);
        memcpy(voice_data, audio_power_on.data, voice_size);
        app_adaptor_speech_recog_txt_msg_ind(text, voice_data, voice_size);
#else   // only for audio file in test mode
        uint32_t voice_size = strlen(AUDIO_POWER_ON) + 1;
        uint8_t * voice_data = lv_mem_alloc(voice_size);
        memcpy(voice_data, AUDIO_POWER_ON, voice_size);
        speech_recog_txt_msg_ind(text, voice_data);
#endif

        /* app_adaptor_speech_recog_nw_search_cnf(NULL); */
    } else if(2 == test_num) {
        char str[] = {"Tell a story"};
        char * text = (char *)lv_mem_alloc(strlen(str) + 1);
        memcpy(text, str, strlen(str) + 1);
        app_adaptor_speech_recog_nw_search_cnf(text);
        char new_text[] = {"Heimaojingzhang di1ji jiaxizhenzuo - kuwoyinyue"};
        text = (char *)lv_mem_alloc(strlen(new_text) + 1);
        memcpy(text, new_text, strlen(new_text) + 1);
        app_adaptor_speech_recog_audio_msg_ind(text, 0);
    } else {
        char str[] = {"Stories list"};
        char * text = (char *)lv_mem_alloc(strlen(str) + 1);
        memcpy(text, str, strlen(str) + 1);
        app_adaptor_speech_recog_nw_search_cnf(text);
        char new_text[] = {"Heimaojingzhang di20ji jiaxizhenzuo - kuwoyinyue"};
        uint32_t len = strlen(new_text) + 1;
        text = (char *)lv_mem_alloc(len);
        memcpy(text, new_text, len);
        app_adaptor_speech_recog_audio_msg_ind(text, 1);
        text = (char *)lv_mem_alloc(len);
        memcpy(text, "Heimaojingzhang di21ji jiaxizhenzuo - kuwoyinyue", len);
        app_adaptor_speech_recog_audio_msg_ind(text, 2);
        text = (char *)lv_mem_alloc(len);
        memcpy(text, "Heimaojingzhang di22ji jiaxizhenzuo - kuwoyinyue", len);
        app_adaptor_speech_recog_audio_msg_ind(text, 3);
        text = (char *)lv_mem_alloc(len);
        memcpy(text, "Heimaojingzhang di23ji jiaxizhenzuo - kuwoyinyue", len);
        app_adaptor_speech_recog_audio_msg_ind(text, 4);
        text = (char *)lv_mem_alloc(len);
        memcpy(text, "Heimaojingzhang di24ji jiaxizhenzuo - kuwoyinyue", len);
        app_adaptor_speech_recog_audio_msg_ind(text, 5);
        text = (char *)lv_mem_alloc(len);
        memcpy(text, "Heimaojingzhang di25ji jiaxizhenzuo - kuwoyinyue", len);
        app_adaptor_speech_recog_audio_msg_ind(text, 6);
        text = (char *)lv_mem_alloc(len);
        memcpy(text, "Heimaojingzhang di26ji jiaxizhenzuo - kuwoyinyue", len);
        app_adaptor_speech_recog_audio_msg_ind(text, 7);
        text = (char *)lv_mem_alloc(len);
        memcpy(text, "Heimaojingzhang di27ji jiaxizhenzuo - kuwoyinyue", len);
        app_adaptor_speech_recog_audio_msg_ind(text, 8);
        text = (char *)lv_mem_alloc(len);
        memcpy(text, "Heimaojingzhang di28ji jiaxizhenzuo - kuwoyinyue", len);
        app_adaptor_speech_recog_audio_msg_ind(text, 9);
        text = (char *)lv_mem_alloc(len);
        memcpy(text, "Heimaojingzhang di29ji jiaxizhenzuo - kuwoyinyue", len);
        app_adaptor_speech_recog_audio_msg_ind(text, 10);
    }
}

void app_adaptor_speech_recog_nw_search_req(uint8_t * voice_data, uint32_t voice_size)
{
    printf("%s\n", __FUNCTION__);
    if(voice_data) lv_mem_free(voice_data);
    lv_task_t * msg_task = lv_task_create(speech_recog_test_task_cb, 3000, LV_TASK_PRIO_MID, NULL);
    lv_task_once(msg_task);
}

static lv_task_t * speech_recog_test_task = NULL;
static uint16_t cur_sec = 0;
static void speech_recog_audio_test_task_cb(lv_task_t * task)
{
    uint16_t total_sec = 126;
    if(0 == cur_sec) {
        app_adaptor_speech_recog_play_audio_cnf(total_sec);
    } else {
        app_adaptor_speech_recog_play_audio_ind(cur_sec);
        if(total_sec == cur_sec) {
            printf("%s: speech_recog_test_task %p\n", __FUNCTION__, speech_recog_test_task);
            lv_task_del(speech_recog_test_task);
            speech_recog_test_task = NULL;
        }
    }
    if(15 < cur_sec) {
        cur_sec += 5;
    } else if(5 < cur_sec) {
        cur_sec += 2;
    } else {
        cur_sec += 4;
    }

    if(total_sec < cur_sec) {
        cur_sec = total_sec;
    }
}

void app_adaptor_speech_recog_play_audio_req(uint8_t audio_index)
{
    cur_sec = 0;
    speech_recog_test_task = lv_task_create(speech_recog_audio_test_task_cb, 4000, LV_TASK_PRIO_MID, NULL);
    printf("%s: speech_recog_test_task %p\n", __FUNCTION__, speech_recog_test_task);
}

void app_adaptor_speech_recog_stop_audio_req(uint8_t audio_index)
{
    printf("%s: speech_recog_test_task %p\n", __FUNCTION__, speech_recog_test_task);
    if(speech_recog_test_task) {
        lv_task_del(speech_recog_test_task);
        speech_recog_test_task = NULL;
    }
}

#ifdef BUILD_IN_PC_SIMULATOR /*for pc test*/
static lv_task_t * hal_task_test = NULL;
static uint8_t duration_test = 0;
static AUDIO_RECORD_CB_FUNC func_test;
static void hal_task_test_cb(lv_task_t * para)
{
    duration_test++;
    if(15 == duration_test) {
        func_test(MCI_EVENT_EOS, MCI_INFO_RECORDER_CUR_DURATION_MS, 0);
        lv_task_del(hal_task_test);
        hal_task_test = NULL;
        duration_test = 0;
    } else {
        func_test(MCI_EVENT_INFO, MCI_INFO_RECORDER_CUR_DURATION_MS, duration_test * 1000);
    }
}

static void Hal_Record_Buffer_Start_Req_1(uint8_t * buffer, uint32_t bufsize, uint32_t maxDurationMs, AUDIO_RECORD_CB_FUNC func)
{
    func_test = func;
    hal_task_test = lv_task_create(hal_task_test_cb, 1000, LV_TASK_PRIO_MID, NULL);
}

static uint32_t Hal_Record_Buffer_Stop_Req_1(uint32_t * recSize, uint32_t * durationMs)
{
    if(hal_task_test) {
        *recSize = VOICE_MSG_AMR_HEAD_SIZE + duration_test * HAL_AMR_BUFSIZE_PER_SECOND;
        lv_task_del(hal_task_test);
        hal_task_test = NULL;
    } else {
        *recSize = VOICE_MSG_AMR_HEAD_SIZE + 16 * HAL_AMR_BUFSIZE_PER_SECOND;
    }
    duration_test = 0;

    return 0;
}
#endif

#endif

#endif /*USE_LV_WATCH_SPEECH_RECOG*/
